#!/bin/env python
""" A simple imlementation of isopleth finding.

Requires a complete field to work from.

Fields are in the form of Images (U{http://www.pythonware.com/products/pil/}).  Images should be grey-scale, 256 shades.  That is, 1 byte per pixel.

  """

import Image


class ColourError(Exception):
    def __init__(self, value, image):
        self.value = value
        self.image=image
    def __str__(self):
        return repr(self.value)+"\nImage has mode: "+str(self.image.getbands())
 

def gather(image, value, threshold=0):
    """Gathers a list of pixels (locations) that are equal to C{value} +/- C{threshold}.

    @type image: An instance of a PIL Image, 1 byte per pixel.
    @param image: The interpolated field to work from
    @type value: Integer (0-255)
    @param value: the value of the isopleth
    @type threshold: integer
    @param threshold: the number of values either side of the target that are included in the isopleth
    @return: a list of pixels that make up the isopleth.  Each pixel is an (x,y) tuple
    """
    if image.getbands()!=('L',):

        raise ColourError("gather requires grayscale image, that is with one band \"L\"",image)
    included=[]
    for x in range(image.size[0]):
        for y in range(image.size[1]):
            p=image.getpixel((x,y))
            if p >=value-threshold and \
                   p<=value+threshold:                
                included.append((x,y))
    return included


def gather_draw(image, value, threshold=0, highlight=255):
    """Gathers a list of pixels (locations) that are equal to C{value} +/- C{threshold} and returns an image with them highlighted in the given C{highlight} intensity.

    @type image: An instance of a PIL Image, 1 byte per pixel.
    @param image: The interpolated field to work from
    @type value: Integer (0-255)
    @param value: the value of the isopleth
    @type threshold: integer 
    @param threshold: the number of values either side of the target that are included in the isopleth
    @type highlight: integer (0-255)
    @param highlight: the intensity to highlight the isopleth with
    @return: a tuple of
      - a list of pixels that make up the isopleth.  Each pixel is an (x,y) tuple
      - a copy of the original image in which the highlighting has been performed
    """
    try:
        included=gather(image,value,threshold)
    except ColourError, c:
        raise ColourError("wrong mode",image)
    newim=image.copy()
    
    for p in included:
            newim.putpixel(p,highlight)

    return included,newim
